
// st7735.c
#include "../inc/st7735.h"
#include "definitions.h"
#include <inttypes.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../inc/font_16x16.h"
#include "../inc/font_8x8.h"
#include "../inc/ikun.h"
#include "../inc/st7735_hal.h"
#include "../inc/st7735_spi_dma.h"

// 双缓冲显存
static uint16_t frameBuffer[2][ST7735_WIDTH * ST7735_HEIGHT] __ALIGNED(16);
static uint8_t  currentBufferIndex = 0;

// 刷新周期（ms）
#define REFRESH_INTERVAL_MS 100

static uint32_t lastFPSUpdate = 0;
static uint32_t frameCountFPS = 0;
static uint32_t fps           = 0;

// CPOL=1, CPHA=1（ST7735 要求）

// ==================== 初始化函数 ====================

void ST7735_Init(void)
{
    ST7735_HAL_Init();
    ST7735_HAL_SetBacklight(30); // 默认最大亮度

    LCD_RES_Clear(); // 拉低复位
    SYSTICK_DelayMs(10);
    LCD_RES_Set(); // 拉高复位
    SYSTICK_DelayMs(100);

    ST7735_HAL_WriteCommand(ST7735_SWRESET); // Software reset
    SYSTICK_DelayMs(100);
    ST7735_HAL_WriteCommand(ST7735_SLPOUT); // Exit sleep mode
    SYSTICK_DelayMs(100);
#if USE_ST7735S
    ST7735_HAL_WriteCommand(ST7735_FRMCTR1); // Set frame rate
    ST7735_HAL_WriteData(0x01);              // frame rate = fosc/(1*2 + 40) *(160+20)
    ST7735_HAL_WriteData(0x2C);
    ST7735_HAL_WriteData(0x2D);
#elif USE_ST7735R
    ST7735_HAL_WriteCommand(ST7735_FRMCTR2);
    ST7735_HAL_WriteData(0x01);
    ST7735_HAL_WriteData(0x2C);
    ST7735_HAL_WriteData(0x2D);
#endif

    ST7735_HAL_WriteCommand(ST7735_FRMCTR3);
    ST7735_HAL_WriteData(0x01);
    ST7735_HAL_WriteData(0x2C);
    ST7735_HAL_WriteData(0x2D);
    ST7735_HAL_WriteData(0x01);
    ST7735_HAL_WriteData(0x2C);
    ST7735_HAL_WriteData(0x2D);

#if USE_ST7735R
    ST7735_HAL_WriteCommand(ST7735_FRMCTR3); // Set color inversion
    ST7735_HAL_WriteData(0x07);              // 0x07 = normal mode
#endif

    ST7735_HAL_WriteCommand(ST7735_PWCTR1); // Set power control 1
    ST7735_HAL_WriteData(0xA2);
    ST7735_HAL_WriteData(0x02); // GVDD = 4.7v
    ST7735_HAL_WriteData(0x84); // AVDD = VCI * 2

    ST7735_HAL_WriteCommand(ST7735_PWCTR2); // Set power control 2
    ST7735_HAL_WriteData(0xC5);             // VAP = 4.7V + (VCOMH -VCOML)

    ST7735_HAL_WriteCommand(ST7735_PWCTR3); // Set power control 3
    ST7735_HAL_WriteData(0x0A);             // VRH = 4.0V
    ST7735_HAL_WriteData(0x00);             // VCOM = 0V

    ST7735_HAL_WriteCommand(ST7735_PWCTR4); // Set power control 4
    ST7735_HAL_WriteData(0x8A);             // VDV = 0V
    ST7735_HAL_WriteData(0x2A);             // VCOMH = VCOMH + 0.5V

    ST7735_HAL_WriteCommand(ST7735_PWCTR5); // Set power control 5
    ST7735_HAL_WriteData(0x8A);             // VCOMH = 4.0V
    ST7735_HAL_WriteData(0x2A);             // VCOML = -1.0V

#if USE_ST7735S
    ST7735_HAL_WriteCommand(ST7735_GMCTRN1); // Set Gamma correction
    ST7735_HAL_WriteData(0x02);
    ST7735_HAL_WriteData(0x1C);
    ST7735_HAL_WriteData(0x07);
    ST7735_HAL_WriteData(0x12);
    ST7735_HAL_WriteData(0x37);
    ST7735_HAL_WriteData(0x32);
    ST7735_HAL_WriteData(0x29);
    ST7735_HAL_WriteData(0x2D);
    ST7735_HAL_WriteData(0x29);
    ST7735_HAL_WriteData(0x25);
    ST7735_HAL_WriteData(0x2B);
    ST7735_HAL_WriteData(0x39);
    ST7735_HAL_WriteData(0x00);
    ST7735_HAL_WriteData(0x01);
    ST7735_HAL_WriteData(0x03);
    ST7735_HAL_WriteData(0x10);
#else
    ST7735_HAL_WriteCommand(ST7735_GMCTRN1); // Set Gamma correction
    ST7735_HAL_WriteData(0x03);
    ST7735_HAL_WriteData(0x1D);
    ST7735_HAL_WriteData(0x07);
    ST7735_HAL_WriteData(0x06);
    ST7735_HAL_WriteData(0x2E);
    ST7735_HAL_WriteData(0x2C);
    ST7735_HAL_WriteData(0x29);
    ST7735_HAL_WriteData(0x2D);
    ST7735_HAL_WriteData(0x2E);
    ST7735_HAL_WriteData(0x2E);
    ST7735_HAL_WriteData(0x37);
    ST7735_HAL_WriteData(0x3F);
    ST7735_HAL_WriteData(0x00);
    ST7735_HAL_WriteData(0x00);
    ST7735_HAL_WriteData(0x02);
    ST7735_HAL_WriteData(0x10);
#endif

    ST7735_HAL_WriteCommand(ST7735_COLMOD); // Set pixel format
    ST7735_HAL_WriteData(0x05);             // 0x05 = 16-bit/pixel

    ST7735_HAL_WriteCommand(ST7735_MADCTL); // Set display direction
    ST7735_HAL_WriteData(0xC8);             // 0xC8 = RGB order | landscape screen
    // ST7735_HAL_WriteData(0x68); // 0x68 = RGB order | Rotate 90 degrees to the left
    // ST7735_HAL_WriteData(0xA8); // 0xA8 = RGB order | Rotate 90 degrees to the right

    ST7735_HAL_WriteCommand(ST7735_NORON); // Set normal display mode
    SYSTICK_DelayMs(100);
    ST7735_HAL_WriteCommand(ST7735_DISPON); // Turn on display
    SYSTICK_DelayMs(100);

    lastFPSUpdate = SYSTICK_GetTickCounter();
}

// 设置显示区域

void ST7735_SetWindow(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1)
{
    ST7735_HAL_WriteCommand(ST7735_CASET); // Column address set
    ST7735_HAL_WriteData(0);
    ST7735_HAL_WriteData(x0 + 2);
    ST7735_HAL_WriteData(0);
    ST7735_HAL_WriteData(x1 + 2);

    ST7735_HAL_WriteCommand(ST7735_RASET); // Column address set
    ST7735_HAL_WriteData(0);
    ST7735_HAL_WriteData(y0 + 3);
    ST7735_HAL_WriteData(0);
    ST7735_HAL_WriteData(y1 + 3);

    ST7735_HAL_WriteCommand(ST7735_RAMWR); // Memory write
}

// 获取前台显存

uint16_t *ST7735_GetFrameBuffer(void) { return frameBuffer[currentBufferIndex]; }

// 获取后台显存

uint16_t *ST7735_GetBackBuffer(void) { return frameBuffer[1 - currentBufferIndex]; }

// 切换缓冲区

void ST7735_SwapBuffers(void) { currentBufferIndex = 1 - currentBufferIndex; }

// 填充整个屏幕
void ST7735_FillScreen(uint16_t color)
{
    uint16_t *buffer = ST7735_GetFrameBuffer();
    for (int i = 0; i < ST7735_WIDTH * ST7735_HEIGHT; i++)
    {
        buffer[i] = color;
    }
}

void ST7735_FillScreen_Ikun(void)
{
    uint16_t *buffer = ST7735_GetFrameBuffer();
    memcpy((uint8_t *)buffer, (uint8_t *)gImage_ikun, ST7735_WIDTH * ST7735_HEIGHT * 2);
}

// 刷新屏幕

void ST7735_Flush(void)
{
    ST7735_SetWindow(0, 0, ST7735_WIDTH - 1, ST7735_HEIGHT - 1);
    ST7735_SPI_DMA_Transfer(ST7735_GetBackBuffer(), sizeof(frameBuffer[0]));
    // 帧率统计
    frameCountFPS++;
}

// 帧率统计任务

void ST7735_FPSCounterTask(void)
{
    uint32_t now = SYSTICK_GetTickCounter();
    if (now - lastFPSUpdate >= 1000)
    {
        fps           = frameCountFPS;
        frameCountFPS = 0;
        lastFPSUpdate = now;
    }
}

// 刷新任务

void ST7735_Task(void)
{
    ST7735_FPSCounterTask();
    if (ST7735_SPI_DMA_IsIdle())
    {
        ST7735_SwapBuffers();
        ST7735_Flush();
    }
}

// 显示帧率

void ST7735_DrawFPS(uint8_t x, uint8_t y)
{
    char buffer[16];
    sprintf(buffer, "FPS: %lu", fps);
    ST7735_DrawString16x16(x, y, buffer, COLOR_RED, COLOR_BLACK, 0);
}

// 画点

void ST7735_DrawPixel(uint8_t x, uint8_t y, uint16_t color)
{
    if (x < 0 || x >= ST7735_WIDTH || y < 0 || y >= ST7735_HEIGHT)
        return;
    ST7735_GetFrameBuffer()[y * ST7735_WIDTH + x] = color;
}

// 画线（Bresenham算法）

void ST7735_DrawLine(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint16_t color)
{
    int16_t dx = abs(x1 - x0), dy = abs(y1 - y0);
    int16_t sx  = x0 < x1 ? 1 : -1;
    int16_t sy  = y0 < y1 ? 1 : -1;
    int16_t err = dx - dy, e2;

    while (1)
    {
        ST7735_DrawPixel(x0, y0, color);
        if (x0 == x1 && y0 == y1)
            break;
        e2 = 2 * err;
        if (e2 > -dy)
        {
            err -= dy;
            x0 += sx;
        }
        if (e2 < dx)
        {
            err += dx;
            y0 += sy;
        }
    }
}

// 画矩形框

void ST7735_DrawRect(uint8_t x, uint8_t y, int8_t w, int8_t h, uint16_t color)
{
    ST7735_DrawLine(x, y, x + w - 1, y, color);
    ST7735_DrawLine(x, y, x, y + h - 1, color);
    ST7735_DrawLine(x + w - 1, y, x + w - 1, y + h - 1, color);
    ST7735_DrawLine(x, y + h - 1, x + w - 1, y + h - 1, color);
}

// 填充矩形

void ST7735_FillRect(uint8_t x, uint8_t y, int8_t w, int8_t h, uint16_t color)
{
    for (int16_t j = y; j < y + h; j++)
    {
        for (int16_t i = x; i < x + w; i++)
        {
            ST7735_DrawPixel(i, j, color);
        }
    }
}

// 画圆（Bresenham算法）

void ST7735_DrawCircle(uint8_t x0, uint8_t y0, int8_t r, uint16_t color)
{
    int16_t f     = 1 - r;
    int16_t ddF_x = 1, ddF_y = -2 * r;
    int16_t x = 0, y = r;

    ST7735_DrawPixel(x0, y0 + r, color);
    ST7735_DrawPixel(x0, y0 - r, color);
    ST7735_DrawPixel(x0 + r, y0, color);
    ST7735_DrawPixel(x0 - r, y0, color);

    while (x < y)
    {
        if (f >= 0)
        {
            y--;
            ddF_y += 2;
            f += ddF_y;
        }
        x++;
        ddF_x += 2;
        f += ddF_x;

        ST7735_DrawPixel(x0 + x, y0 + y, color);
        ST7735_DrawPixel(x0 - x, y0 + y, color);
        ST7735_DrawPixel(x0 + x, y0 - y, color);
        ST7735_DrawPixel(x0 - x, y0 - y, color);
        ST7735_DrawPixel(x0 + y, y0 + x, color);
        ST7735_DrawPixel(x0 - y, y0 + x, color);
        ST7735_DrawPixel(x0 + y, y0 - x, color);
        ST7735_DrawPixel(x0 - y, y0 - x, color);
    }
}

// 填充圆

void ST7735_FillCircle(uint8_t x0, uint8_t y0, int8_t r, uint16_t color)
{
    for (int16_t y = -r; y <= r; y++)
    {
        for (int16_t x = -r; x <= r; x++)
        {
            if (x * x + y * y <= r * r)
            {
                ST7735_DrawPixel(x0 + x, y0 + y, color);
            }
        }
    }
}

// 画字符（8x8 字体）

void ST7735_DrawChar8x8(uint8_t x, uint8_t y, char ch, uint16_t color, uint16_t bgColor, uint8_t isBg)
{
    const uint8_t *pFont = font_8x8[ch - 0x20];
    for (int row = 0; row < 8; row++)
    {
        for (int col = 0; col < 8; col++)
        {
            if (pFont[row] & (1 << (7 - col)))
            {
                ST7735_DrawPixel(x + col, y + row, color);
            }
            else if (isBg)
            {
                ST7735_DrawPixel(x + col, y + row, bgColor);
            }
        }
    }
}

// 画字符串

void ST7735_DrawString8x8(uint8_t x, uint8_t y, const char *str, uint16_t color, uint16_t bgColor, uint8_t isBg)
{
    while (*str)
    {
        ST7735_DrawChar8x8(x, y, *str++, color, bgColor, isBg);
        x += 8;
    }
}

// 画字符（16x16 字体）

void ST7735_DrawChar16x16(uint8_t x, uint8_t y, char ch, uint16_t color, uint16_t bgColor, uint8_t isBg)
{
    if (ch < 0x20 || ch > 0x7F)
        return; // 仅支持 ASCII 0x20 ~ 0x7F

    const uint8_t *pFont = font_16x16[ch - 0x20]; // 从 font_16x16 获取字符点阵

    for (int row = 0; row < 16; row++)
    {
        uint8_t line = pFont[row];
        for (int col = 0; col < 8; col++)
        {
            int16_t pixelX = x + col;
            int16_t pixelY = y + row;

            if (pixelX >= ST7735_WIDTH || pixelY >= ST7735_HEIGHT)
                continue;

            if (line & (0x80 >> col))
            {
                ST7735_DrawPixel(pixelX, pixelY, color);
            }
            else if (isBg)
            {
                ST7735_DrawPixel(pixelX, pixelY, bgColor);
            }
        }
    }
}

// st7735.c 中新增函数

void ST7735_DrawString16x16(uint8_t x, uint8_t y, const char *str, uint16_t color, uint16_t bgColor, uint8_t isBg)
{
    while (*str)
    {
        ST7735_DrawChar16x16(x, y, *str++, color, bgColor, isBg);
        x += 8; // 每个字符宽度为 8 像素（16x16 字体，每个字节 8 位）

        // 检查是否超出屏幕宽度
        if (x + 8 > ST7735_WIDTH)
        {
            x = 0;
            y += 16; // 换行
        }

        if (y + 16 > ST7735_HEIGHT)
            break; // 超出屏幕高度
    }
}

void ST7735_Printf8x8(uint8_t x, uint8_t y, uint16_t color, uint16_t bgColor, uint8_t isBg, const char *format, ...)
{
    char    buffer[256];
    va_list args;
    va_start(args, format);
    vsnprintf(buffer, sizeof(buffer), format, args);
    va_end(args);

    ST7735_DrawString8x8(x, y, buffer, color, bgColor, isBg);
}

void ST7735_Printf16x16(uint8_t x, uint8_t y, uint16_t color, uint16_t bgColor, uint8_t isBg, const char *format, ...)
{
    char    buffer[256];
    va_list args;
    va_start(args, format);
    vsnprintf(buffer, sizeof(buffer), format, args);
    va_end(args);

    ST7735_DrawString16x16(x, y, buffer, color, bgColor, isBg);
}

void ST7735_Printf8x8AutoWrap(uint8_t    *x,
                              uint8_t    *y,
                              uint16_t    color,
                              uint16_t    bgColor,
                              uint8_t     isBg,
                              const char *format,
                              ...)
{
    char    buffer[256];
    va_list args;
    va_start(args, format);
    vsnprintf(buffer, sizeof(buffer), format, args);
    va_end(args);

    size_t len = strlen(buffer);
    ST7735_DrawString8x8(*x, *y, buffer, color, bgColor, isBg);

    *x += len * 8; // 每个字符宽度为 8 像素
    if (*x >= ST7735_WIDTH)
    {
        *x = 0;
        *y += 8;
    }

    if (*y + 8 > ST7735_HEIGHT)
    {
        *y = 0; // 滚动到顶部
    }
}

void ST7735_Printf16x16AutoWrap(uint8_t    *x,
                                uint8_t    *y,
                                uint16_t    color,
                                uint16_t    bgColor,
                                uint8_t     isBg,
                                const char *format,
                                ...)
{
    char    buffer[256];
    va_list args;
    va_start(args, format);
    vsnprintf(buffer, sizeof(buffer), format, args);
    va_end(args);

    const char *str      = buffer;
    int16_t     startX   = *x;
    int16_t     currentX = startX;
    int16_t     currentY = *y;

    while (*str)
    {
        if (*str == '\n')
        {
            // 换行
            currentX = startX;
            currentY += 16;
            if (currentY + 16 > ST7735_HEIGHT)
            {
                currentY = 0; // 屏幕底部换行到顶部
            }
            str++;
            continue;
        }

        // 显示字符
        ST7735_DrawChar16x16(currentX, currentY, *str++, color, bgColor, isBg);

        // 移动到下一个字符位置
        currentX += 8;

        // 检查是否超出宽度
        if (currentX + 8 > ST7735_WIDTH)
        {
            currentX = startX;
            currentY += 16;
            if (currentY + 16 > ST7735_HEIGHT)
            {
                currentY = 0; // 屏幕底部换行到顶部
            }
        }
    }

    // 更新坐标
    *x = currentX;
    *y = currentY;
}